<#--
 # MCreator (https://mcreator.net/)
 # Copyright (C) 2020 Pylo and contributors
 #
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation, either version 3 of the License, or
 # (at your option) any later version.
 #
 # This program is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 # GNU General Public License for more details.
 #
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <https://www.gnu.org/licenses/>.
 #
 # Additional permission for code generator templates (*.ftl files)
 #
 # As a special exception, you may create a larger work that contains part or
 # all of the MCreator code generator templates (*.ftl files) and distribute
 # that work under terms of your choice, so long as that work isn't itself a
 # template for code generation. Alternatively, if you modify or redistribute
 # the template itself, you may (at your option) remove this special exception,
 # which will cause the template and the resulting code generator output files
 # to be licensed under the GNU General Public License without this special
 # exception.
-->

<#-- @formatter:off -->
<#include "mcitems.ftl">
<#include "procedures.java.ftl">

package ${package}.world.structure;

@Mod.EventBusSubscriber public class ${name}Structure {

	private static Feature<NoFeatureConfig> feature = null;
	private static ConfiguredFeature<?, ?> configuredFeature = null;

	@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD) private static class FeatureRegisterHandler {

		@SubscribeEvent public static void registerFeature(RegistryEvent.Register<Feature<?>> event) {
			feature = new Feature<NoFeatureConfig>(NoFeatureConfig.field_236558_a_) {
				@Override public boolean generate(ISeedReader world, ChunkGenerator generator, Random random, BlockPos pos, NoFeatureConfig config) {
					int ci = (pos.getX() >> 4) << 4;
					int ck = (pos.getZ() >> 4) << 4;

					RegistryKey<World> dimensionType = world.getWorld().getDimensionKey();
					boolean dimensionCriteria = false;

    				<#list data.spawnWorldTypes as worldType>
						<#if worldType=="Surface">
							if(dimensionType == World.OVERWORLD)
								dimensionCriteria = true;
						<#elseif worldType=="Nether">
							if(dimensionType == World.THE_NETHER)
								dimensionCriteria = true;
						<#elseif worldType=="End">
							if(dimensionType == World.THE_END)
								dimensionCriteria = true;
						<#else>
							if(dimensionType == RegistryKey.getOrCreateKey(Registry.WORLD_KEY,
									new ResourceLocation("${generator.getResourceLocationForModElement(worldType.toString().replace("CUSTOM:", ""))}")))
								dimensionCriteria = true;
						</#if>
					</#list>

					if(!dimensionCriteria)
						return false;

					if ((random.nextInt(1000000) + 1) <= ${data.spawnProbability}) {
						int count = random.nextInt(${data.maxCountPerChunk - data.minCountPerChunk + 1}) + ${data.minCountPerChunk};
						for(int a = 0; a < count; a++) {
							int i = ci + random.nextInt(16);
							int k = ck + random.nextInt(16);
							int j = world.getHeight(Heightmap.Type.<#if data.surfaceDetectionType=="First block">WORLD_SURFACE_WG<#elseif data.surfaceDetectionType=="First motion blocking block">OCEAN_FLOOR_WG</#if>, i, k);

							<#if data.spawnLocation=="Ground">
								j -= 1;
							<#elseif data.spawnLocation=="Air">
								j += random.nextInt(50) + 16;
							<#elseif data.spawnLocation=="Underground">
								j = Math.abs(random.nextInt(Math.max(1, j)) - 24);
							</#if>

							<#if data.restrictionBlocks?has_content>
								BlockState blockAt = world.getBlockState(new BlockPos(i, j, k));
								boolean blockCriteria = false;
								<#list data.restrictionBlocks as restrictionBlock>
									if (blockAt.getBlock() == ${mappedBlockToBlock(restrictionBlock)})
										blockCriteria = true;
								</#list>
								if (!blockCriteria)
									continue;
							</#if>

							<#if data.randomlyRotateStructure>
								Rotation rotation = Rotation.values()[random.nextInt(3)];
								Mirror mirror = Mirror.values()[random.nextInt(2)];
							<#else>
								Rotation rotation = Rotation.NONE;
								Mirror mirror = Mirror.NONE;
							</#if>

							BlockPos spawnTo = new BlockPos(i + ${data.spawnXOffset}, j + ${data.spawnHeightOffset}, k + ${data.spawnZOffset});

							int x = spawnTo.getX();
							int y = spawnTo.getY();
							int z = spawnTo.getZ();

							<#if hasProcedure(data.generateCondition)>
							if (!<@procedureOBJToConditionCode data.generateCondition/>)
								continue;
							</#if>

							Template template = world.getWorld().getStructureTemplateManager().getTemplateDefaulted(new ResourceLocation("${modid}" ,"${data.structure}"));

							if (template == null)
								return false;

							template.func_237144_a_(world, spawnTo,
									new PlacementSettings()
											.setRotation(rotation)
											.setRandom(random)
											.setMirror(mirror)
											.addProcessor(BlockIgnoreStructureProcessor.${data.ignoreBlocks})
											.setChunk(null)
											.setIgnoreEntities(false), random);

							<#if hasProcedure(data.onStructureGenerated)>
								<@procedureOBJToCode data.onStructureGenerated/>
							</#if>
						}
					}

					return true;
				}
			};

			configuredFeature = feature
					.withConfiguration(IFeatureConfig.NO_FEATURE_CONFIG)
					.withPlacement(Placement.NOPE.configure(IPlacementConfig.NO_PLACEMENT_CONFIG));

			event.getRegistry().register(feature.setRegistryName("${registryname}"));
			Registry.register(WorldGenRegistries.CONFIGURED_FEATURE, new ResourceLocation("${modid}:${registryname}"), configuredFeature);
		}

	}

	@SubscribeEvent public static void addFeatureToBiomes(BiomeLoadingEvent event) {
		<#if data.restrictionBiomes?has_content>
				boolean biomeCriteria = false;
			<#list data.restrictionBiomes as restrictionBiome>
				<#if restrictionBiome.canProperlyMap()>
					if (new ResourceLocation("${restrictionBiome}").equals(event.getName()))
						biomeCriteria = true;
				</#if>
			</#list>
				if (!biomeCriteria)
					return;
		</#if>

		event.getGeneration().getFeatures(GenerationStage.Decoration.
				<#if data.spawnLocation=="Ground">SURFACE_STRUCTURES
				<#elseif data.spawnLocation=="Air">RAW_GENERATION
				<#elseif data.spawnLocation=="Underground">UNDERGROUND_STRUCTURES</#if>)
			 .add(() -> configuredFeature);
	}

}
<#-- @formatter:on -->
